package edu.lmu.cs.forney.roflkode.entities;

import edu.lmu.cs.forney.util.Log;

/**
 * Superclass for all types.
 */
public class Type extends Declarable {

    public static final Type INT = new Type("INT");
    public static final Type NUMBR = new Type("NUMBR");
    public static final Type BOOL = new Type("BOOL");
    public static final Type KAR = new Type("KAR");
    public static final Type YARN = new Type("YARN");

    /**
     * A type representing the union of all types.  It is assigned to
     * an entity whose typename is not in scope.  It is compatible with
     * all other types.  It exists to avoid spurious errors during
     * compilation.
     */
    public static final Type ARBITRARY = new Type("<arbitrary>");

    /**
     * The type whose sole member is the literal null.
     */
    public static final Type NULL_TYPE = new Type("<type_of_null>");

    /**
     * A type representing the union of the string type and all
     * array types.  This is used for the parameter of the special
     * length function from the standard library.
     */
    public static final Type LIST_OR_YARN = new Type("<list_or_yarn>");

    // The type which is an list of this type.  It will be null
    // unless needed.  When it is needed, it will be created.
    private ArrayType listOfThisType = null;

    /**
     * Constructs a type with the given name.
     */
    Type(String name) {
        super(name);
    }

    /**
     * Returns whether this type is a reference type.
     */
    public boolean isReference() {
        return this == YARN
            || this instanceof ArrayType
            || this instanceof BukkitType
            || this == LIST_OR_YARN
            || this == ARBITRARY;
    }

    /**
     * Returns whether this type is an arithmetic type.
     */
    public boolean isArithmetic() {
        return this == INT || this == NUMBR;
    }

    /**
     * Returns the type that is an list of this type, lazily
     * creating it.
     */
    public Type list() {
        if (listOfThisType == null) {
            listOfThisType = new ArrayType(this);
        }
        return listOfThisType;
    }

    /**
     * A default implementation that does nothing, since many type
     * subclasses actually need no analysis.
     */
    public void analyze(Log log, SymbolTable table) {
    }
}
